﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using System.Threading;
using System.Security.Principal;
using Locator.Inventory;
using Locator.LcboServices.LcboInventoryService.Services;
using Locator.LcboServices.LcboStoresService.Services;
using DataAccess.UnitTests;
using Locator.LcboServices.BusinessEntities;
using DataAccess.BusinessEntities;

namespace Inventory.Tests
{
    [TestFixture]
    public class InventoryControllerTests : DataTestBase
    {
        private const string UserName = "jmclachl";
        private const string Heineken6x330ml = "Heineken 6x330.00 ml";
        private const string MikeWeirChardonnay750ml = "Mike Weir Wine Chardonnay (V) 750 ml";

        [SetUp]
        public void InitializeUnitOfWork()
        {
            this.InitializeRepositories();
        }

        [Test]
        public void OneStoreOneProductNoNewOrChangedStores()
        {
            Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(UserName), new string[] { });
            LcboInventoryServiceAgentStub lcboServiceAgentStub = new LcboInventoryServiceAgentStub();
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 1, City = "Springfield", NumberInStock = 20, ProductId = 18, StreetAddress = "123 Fake St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 2, City = "Springfield", NumberInStock = 30, ProductId = 18, StreetAddress = "782 Evergreen Terrace" });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 3, City = "Ogdenville", NumberInStock = 40, ProductId = 18, StreetAddress = "456 Some St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 4, City = "North Haverbrook", NumberInStock = 50, ProductId = 18, StreetAddress = "567 Another St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 998, City = "Capitol City", NumberInStock = 60, ProductId = 18, StreetAddress = "1 Mockafella Plaza" });
            using (InventoryController controller = new InventoryController(lcboServiceAgentStub, null, this.DomainContext))
            {
                var storesWithInventory = controller.GetInventoriesWithRequest(new BusinessEntities.InventoryRequest() { ProductId = 18, StoreNumber = 1 });
                Assert.AreEqual(1, storesWithInventory.Count);
                Assert.AreEqual(1, storesWithInventory[0].Store.StoreNumber);
                Assert.AreEqual(1, storesWithInventory[0].Inventory.Count);
                Assert.AreEqual(20, storesWithInventory[0].Inventory[0].NumberInStock);
                Assert.AreEqual(Heineken6x330ml, storesWithInventory[0].Inventory[0].Product.Name);
            }
        }

        [Test]
        public void UsersStoresOneProductNoNewOrChangedStores()
        {
            Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(UserName), new string[] { });
            LcboInventoryServiceAgentStub lcboServiceAgentStub = new LcboInventoryServiceAgentStub();
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 1, City = "Springfield", NumberInStock = 20, ProductId = 18, StreetAddress = "123 Fake St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 2, City = "Springfield", NumberInStock = 30, ProductId = 18, StreetAddress = "782 Evergreen Terrace" });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 3, City = "Ogdenville", NumberInStock = 40, ProductId = 18, StreetAddress = "456 Some St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 4, City = "North Haverbrook", NumberInStock = 50, ProductId = 18, StreetAddress = "567 Another St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 998, City = "Capitol City", NumberInStock = 60, ProductId = 18, StreetAddress = "1 Mockafella Plaza" });
            using (InventoryController controller = new InventoryController(lcboServiceAgentStub, null, this.DomainContext))
            {
                var storesWithInventory = controller.GetInventoriesWithRequest(new BusinessEntities.InventoryRequest() { ProductId = 18, StoreNumberType = BusinessEntities.StoreNumberType.AllUsersStores });
                Assert.AreEqual(3, storesWithInventory.Count);
                Assert.AreEqual(1, storesWithInventory[0].Store.StoreNumber);
                Assert.AreEqual(2, storesWithInventory[1].Store.StoreNumber);
                Assert.AreEqual(3, storesWithInventory[2].Store.StoreNumber);
                Assert.AreEqual(1, storesWithInventory[0].Inventory.Count);
                Assert.AreEqual(1, storesWithInventory[1].Inventory.Count);
                Assert.AreEqual(1, storesWithInventory[2].Inventory.Count);
                Assert.AreEqual(20, storesWithInventory[0].Inventory[0].NumberInStock);
                Assert.AreEqual(30, storesWithInventory[1].Inventory[0].NumberInStock);
                Assert.AreEqual(Heineken6x330ml, storesWithInventory[0].Inventory[0].Product.Name);
            }
        }

        [Test]
        public void UsersStoresUsersProductNoNewOrChangedStores()
        {
            Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(UserName), new string[] { });
            LcboInventoryServiceAgentStub lcboServiceAgentStub = new LcboInventoryServiceAgentStub();
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 1, City = "Springfield", NumberInStock = 20, ProductId = 18, StreetAddress = "123 Fake St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 2, City = "Springfield", NumberInStock = 30, ProductId = 18, StreetAddress = "782 Evergreen Terrace" });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 3, City = "Ogdenville", NumberInStock = 40, ProductId = 18, StreetAddress = "456 Some St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 4, City = "North Haverbrook", NumberInStock = 50, ProductId = 18, StreetAddress = "567 Another St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 998, City = "Capitol City", NumberInStock = 60, ProductId = 18, StreetAddress = "1 Mockafella Plaza" });

            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 1, City = "Springfield", NumberInStock = 21, ProductId = 26, StreetAddress = "123 Fake St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 2, City = "Springfield", NumberInStock = 31, ProductId = 26, StreetAddress = "782 Evergreen Terrace" });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 3, City = "Ogdenville", NumberInStock = 41, ProductId = 26, StreetAddress = "456 Some St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 4, City = "North Haverbrook", NumberInStock = 51, ProductId = 26, StreetAddress = "567 Another St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 998, City = "Capitol City", NumberInStock = 61, ProductId = 26, StreetAddress = "1 Mockafella Plaza" });

            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 1, City = "Springfield", NumberInStock = 22, ProductId = 99, StreetAddress = "123 Fake St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 2, City = "Springfield", NumberInStock = 32, ProductId = 99, StreetAddress = "782 Evergreen Terrace" });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 3, City = "Ogdenville", NumberInStock = 42, ProductId = 99, StreetAddress = "456 Some St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 4, City = "North Haverbrook", NumberInStock = 52, ProductId = 99, StreetAddress = "567 Another St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 998, City = "Capitol City", NumberInStock = 62, ProductId = 99, StreetAddress = "1 Mockafella Plaza" });

            using (InventoryController controller = new InventoryController(lcboServiceAgentStub, null, this.DomainContext))
            {
                var storesWithInventory = controller.GetInventoriesWithRequest(new BusinessEntities.InventoryRequest() { ProductIdType = BusinessEntities.ProductIdType.AllUsersProducts, StoreNumberType = BusinessEntities.StoreNumberType.AllUsersStores });
                Assert.AreEqual(3, storesWithInventory.Count);
                Assert.AreEqual(1, storesWithInventory[0].Store.StoreNumber);
                Assert.AreEqual(2, storesWithInventory[1].Store.StoreNumber);
                Assert.AreEqual(3, storesWithInventory[2].Store.StoreNumber);
                Assert.AreEqual(3, storesWithInventory[0].Inventory.Count);
                Assert.AreEqual(3, storesWithInventory[1].Inventory.Count);
                Assert.AreEqual(3, storesWithInventory[2].Inventory.Count);
                Assert.AreEqual(20, storesWithInventory[0].Inventory[0].NumberInStock);
                Assert.AreEqual(30, storesWithInventory[1].Inventory[0].NumberInStock);
                Assert.AreEqual(21, storesWithInventory[0].Inventory[1].NumberInStock);
                Assert.AreEqual(Heineken6x330ml, storesWithInventory[0].Inventory[0].Product.Name);
                Assert.AreEqual(MikeWeirChardonnay750ml, storesWithInventory[0].Inventory[1].Product.Name);
            }
        }

        [Test]
        public void AllStoresUsersProductNoNewOrChangedStores()
        {
            Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(UserName), new string[] { });
            LcboInventoryServiceAgentStub lcboServiceAgentStub = new LcboInventoryServiceAgentStub();
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 1, City = "Springfield", NumberInStock = 20, ProductId = 18, StreetAddress = "123 Fake St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 2, City = "Springfield", NumberInStock = 30, ProductId = 18, StreetAddress = "782 Evergreen Terrace" });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 3, City = "Ogdenville", NumberInStock = 40, ProductId = 18, StreetAddress = "456 Some St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 4, City = "North Haverbrook", NumberInStock = 50, ProductId = 18, StreetAddress = "567 Another St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 998, City = "Capitol City", NumberInStock = 60, ProductId = 18, StreetAddress = "1 Mockafella Plaza" });

            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 1, City = "Springfield", NumberInStock = 21, ProductId = 26, StreetAddress = "123 Fake St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 2, City = "Springfield", NumberInStock = 31, ProductId = 26, StreetAddress = "782 Evergreen Terrace" });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 3, City = "Ogdenville", NumberInStock = 41, ProductId = 26, StreetAddress = "456 Some St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 4, City = "North Haverbrook", NumberInStock = 51, ProductId = 26, StreetAddress = "567 Another St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 998, City = "Capitol City", NumberInStock = 61, ProductId = 26, StreetAddress = "1 Mockafella Plaza" });

            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 1, City = "Springfield", NumberInStock = 22, ProductId = 99, StreetAddress = "123 Fake St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 2, City = "Springfield", NumberInStock = 32, ProductId = 99, StreetAddress = "782 Evergreen Terrace" });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 3, City = "Ogdenville", NumberInStock = 42, ProductId = 99, StreetAddress = "456 Some St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 4, City = "North Haverbrook", NumberInStock = 52, ProductId = 99, StreetAddress = "567 Another St." });
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 998, City = "Capitol City", NumberInStock = 62, ProductId = 99, StreetAddress = "1 Mockafella Plaza" });

            using (InventoryController controller = new InventoryController(lcboServiceAgentStub, null, this.DomainContext))
            {
                var storesWithInventory = controller.GetInventoriesWithRequest(new BusinessEntities.InventoryRequest() { ProductIdType = BusinessEntities.ProductIdType.AllUsersProducts, StoreNumberType = BusinessEntities.StoreNumberType.AllStores });
                Assert.AreEqual(5, storesWithInventory.Count);
                Assert.AreEqual(1, storesWithInventory[0].Store.StoreNumber);
                Assert.AreEqual(2, storesWithInventory[1].Store.StoreNumber);
                Assert.AreEqual(3, storesWithInventory[2].Store.StoreNumber);
                Assert.AreEqual(3, storesWithInventory[0].Inventory.Count);
                Assert.AreEqual(3, storesWithInventory[1].Inventory.Count);
                Assert.AreEqual(3, storesWithInventory[2].Inventory.Count);
                Assert.AreEqual(20, storesWithInventory[0].Inventory[0].NumberInStock);
                Assert.AreEqual(30, storesWithInventory[1].Inventory[0].NumberInStock);
                Assert.AreEqual(21, storesWithInventory[0].Inventory[1].NumberInStock);
                Assert.AreEqual(Heineken6x330ml, storesWithInventory[0].Inventory[0].Product.Name);
                Assert.AreEqual(MikeWeirChardonnay750ml, storesWithInventory[0].Inventory[1].Product.Name);
            }
        }

        [Test]
        public void ChangedStoreNotDetected()
        {
            // Change an existing store then check that it was changed back to normal
            var store998 = this.DomainContext.Stores.Single(s => s.Id == 998);
            store998.Address = "Not 1 Mockafella Plaza";
            this.DomainContext.SaveChanges();

            Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(UserName), new string[] { });
            LcboInventoryServiceAgentStub lcboServiceAgentStub = new LcboInventoryServiceAgentStub();
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 998, City = "Capitol City", NumberInStock = 60, ProductId = 18, StreetAddress = "1 Mockafella Plaza" });
            LcboStoresServiceAgentStub lcboStoresServiceAgentStub = new LcboStoresServiceAgentStub();
            lcboStoresServiceAgentStub.GetLocationDetailsResponse = new LcboStoreInformation() { AddressLine = "1 Mockafella Plaza", City = "Capitol City", StoreNumber = 998 };
            using (InventoryController controller = new InventoryController(lcboServiceAgentStub, lcboStoresServiceAgentStub, this.DomainContext))
            {
                var storesWithInventory = controller.GetInventoriesWithRequest(new BusinessEntities.InventoryRequest() { ProductId = 18, StoreNumber = 998 });
                store998 = this.DomainContext.Stores.Single(s => s.Id == 998);
            }

            Assert.AreEqual("Not 1 Mockafella Plaza", store998.Address);
        }

        [Test]
        public void NewStoreDetected()
        {
            var store998 = this.DomainContext.Stores.Single(s => s.Id == 998);
            this.DomainContext.Delete<Store>(998);
            this.DomainContext.SaveChanges();

            Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(UserName), new string[] { });
            LcboInventoryServiceAgentStub lcboServiceAgentStub = new LcboInventoryServiceAgentStub();
            lcboServiceAgentStub.RetireveMatches3Response.Add(new LcboInventoryData2() { StoreNumber = 998, City = "Capitol City", NumberInStock = 60, ProductId = 18, StreetAddress = "1 Mockafella Plaza" });
            LcboStoresServiceAgentStub lcboStoresServiceAgentStub = new LcboStoresServiceAgentStub();
            lcboStoresServiceAgentStub.GetLocationDetailsResponse = new LcboStoreInformation() { AddressLine = store998.Address, City = store998.City, StoreNumber = store998.Id, Latitude = store998.Latitude, Longitude = store998.Longitude };
            using (InventoryController controller = new InventoryController(lcboServiceAgentStub, lcboStoresServiceAgentStub, this.DomainContext))
            {
                var storesWithInventory = controller.GetInventoriesWithRequest(new BusinessEntities.InventoryRequest() { ProductId = 18, StoreNumber = 998 });
                store998 = this.DomainContext.Stores.Single(s => s.Id == 998);
            }

            Assert.AreEqual("1 Mockafella Plaza", store998.Address);
        }
    }
}